<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>日期选择器示例（兼容版）</title>
  <style>
    input:invalid+span:after {
      content: '✖';
      padding-left: 5px;
    }

    input:valid+span:after {
      content: '✓';
      padding-left: 5px;
    }
  </style>
</head>

<body>
  <form>
      <div class="nativeDatePicker">
        <label for="bday">输入你的生日：</label>
        <input type="date" id="bday" name="bday">
        <span class="validity"></span>
      </div>
      <p class="fallbackLabel">输入你的生日：</p>
      <div class="fallbackDatePicker">
        <span>
          <select id="year" name="year"> </select>
          <label for="year">年</label>
        </span>
        <span>
          <select id="month" name="month">
            <option selected>一</option>
            <option>二</option>
            <option>三</option>
            <option>四</option>
            <option>五</option>
            <option>六</option>
            <option>七</option>
            <option>八</option>
            <option>九</option>
            <option>十</option>
            <option>十一</option>
            <option>十二</option>
          </select>
          <label for="month">月</label>
        </span>
        <span>
          <select id="day" name="day"></select>
          <label for="day">日</label>
        </span>
      </div>
  </form>

<script>
// 定义变量
var nativePicker = document.querySelector('.nativeDatePicker');
var fallbackPicker = document.querySelector('.fallbackDatePicker');
var fallbackLabel = document.querySelector('.fallbackLabel');

var yearSelect = document.querySelector('#year');
var monthSelect = document.querySelector('#month');
var daySelect = document.querySelector('#day');

// 默认隐藏兼容模式
fallbackPicker.style.display = 'none';
fallbackLabel.style.display = 'none';

// 测试是否支持日期输入框
var test = document.createElement('input');

try {
  test.type = 'date';
} catch (e) {
  console.log(e.description);
}

// 若支持，运行 if() {} 块内代码
if(test.type === 'text') {
  // 隐藏本地日期输入框，显示兼容模式
  nativePicker.style.display = 'none';
  fallbackPicker.style.display = 'block';
  fallbackLabel.style.display = 'block';

  // 动态生成年和日（月份始终不变，直接硬编码）
  populateDays();
  populateYears();
}

function isLeapYear(year) {
  return (new Date(year, 1, 29).getMonth() === 1);
}

function dayOfMonth(year, month) {
  switch (month) {
    case '一': case '三': case '五': case '七': case '八': case '十': case '十二':
      return 31;
    case '四': case '六': case '九': case '十一':
      return 30;
    case '二':
      return isLeapYear(year) ? 29 : 28;
    default:
      return 0;
  }
}

function populateDays() {
  // 删除日期 <select> 中所有的 <option> 元素，为下次注入作准备。
  while(daySelect.firstChild) {
    daySelect.removeChild(daySelect.firstChild);
  }

  var dayNum = dayOfMonth(Number(yearSelect.value), monthSelect.value);

  // 为日期 <select> 注入正确数量的新 <option> 元素。
  for(var i = 1; i <= dayNum; i++) {
    var option = document.createElement('option');
    option.textContent = i;
    daySelect.appendChild(option);
  }

  // 如果设置过上一个日期，将 daySelect 的值设置为之前的日期，从而避免在修改年份时日期跳回 1。
  if(previousDay) {
    daySelect.value = previousDay;

    // 以下代码修正“上一个日期大于当前”问题（比如之前是1月31日，将月份修改为2）。
    if(daySelect.value === "") {
      daySelect.value = previousDay - 1;
    }

    if(daySelect.value === "") {
      daySelect.value = previousDay - 2;
    }

    if(daySelect.value === "") {
      daySelect.value = previousDay - 3;
    }
  }
}

function populateYears() {
  // 取当前年份的数值
  var date = new Date();
  var year = date.getFullYear();

  // 在年份 <select> 注入当前你年份及之前的100年
  for(var i = 0; i <= 100; i++) {
    var option = document.createElement('option');
    option.textContent = (year - i).toString();
    yearSelect.appendChild(option);
  }
}

// 在修改月份或年份的 <select> 时，重新运行 populateDays() 使日期有效。
yearSelect.onchange = function() { populateDays(); }

monthSelect.onchange = function() { populateDays(); }

// 前一次日期选择
var previousDay;

// 更新上一轮设置的日期，参见 populateDays()
daySelect.onchange = function() { previousDay = daySelect.value; }
</script>
</body>

</html>
